<!-- 模板 -->
<template>
  <view>
    <view v-for="(item, index) in props.formItems" :key="index">
      <component
        :is="item.name"
        :ref="item.id + '_item'"
        v-model:value="_value[item.id]"
        v-model:formData="_value"
        :formItem="item"
        v-bind="item.props"
        :index="index"
        :readonly="item.perm === 'R'"
        :rule="rules[item.id]"
        :hidden="!showItem(item)"
        @labelShow="labelShow"
      />
    </view>
  </view>
</template>
<script lang="ts">
  import { defineComponent } from 'vue';
  import componentExport from '@/components/form/ComponentExport';
  export default defineComponent({
    components: componentExport,
  });
</script>

<script setup lang="ts">
  import { ref, computed, watch, watchEffect } from 'vue';
  import { onLoad, onShow } from '@dcloudio/uni-app';
  import { FormItemModel, FormRuleModel } from '@/services/model/formModel';
  import { isDef, isNotEmpty } from '@/utils/is';
  import {
    strCompareOptions,
    strArrCompareOptions,
    numCompareOptions,
    orgCompareOptions,
    timeCompareOptions,
    timeArrCompareOptions,
  } from '@/utils/CompareOptions';

  const emits = defineEmits(['update:formData', 'submit']);

  const props = defineProps({
    formData: {
      type: Object,
      default: () => {
        return {};
      },
    },
    formItems: {
      type: Array<FormItemModel>,
      default: () => [],
    },
    formConfig: {
      type: Object,
      default: () => {
        return {
          ruleType: 'SIMPLE',
          rules: [],
        };
      },
    },
  });

  /** 隐藏item */
  const hideFieldIds = ref<string[]>([]);

  /** 计算属性：_value */
  const _value = computed({
    get() {
      return props.formData;
    },
    set(val) {
      emits('update:formData', val);
    },
  });

  /**
   * 解析表单配置
   * @param forms 表单配置
   * @param map 集合
   */
  const loadFormItemMap = (forms: FormItemModel[], map: Map<string, any>) => {
    forms.forEach((item) => {
      if (item.name === 'TableList') {
        map.set(item.id, item);
        loadFormItemMap(item.props.columns, map);
      } else if (item.name === 'SpanLayout') {
        loadFormItemMap(item.props.items, map);
      } else {
        map.set(item.id, item);
      }
    });
  };

  /** 表单配置 */
  const formItemMap = computed(() => {
    const map = new Map();
    loadFormItemMap(props.formItems, map);
    return map;
  });

  /** 表单规则 */
  const rules = ref<FormRuleModel>({});

  /**
   * 初始化表单数据
   * @param forms formItems
   * @param rules 规则
   */
  const loadFormConfig = (forms: any, rules: any) => {
    forms.forEach((item: FormItemModel) => {
      if (item.name === 'SpanLayout') {
        loadFormConfig(item.props.items, rules);
      } else {
        _value.value[item.id] =
          isNotEmpty(props.formData) && isDef(props.formData[item.id])
            ? props.formData[item.id]
            : item.value;
        if (item.props.required && showItem(item)) {
          rules[item.id] = [
            {
              validator: (val: any) => {
                return isNotEmpty(val);
              },
              message: `请完成${item.title}`,
              trigger: 'onBlur',
            },
          ];
        } else {
          rules[item.id] = [];
        }
      }
    });
  };

  /**
   * 是否显示item
   */
  const showItem = (item: FormItemModel) => {
    if (hideFieldIds.value.indexOf(item.id) !== -1) {
      return false;
    }
    //先这样改吧。。
    return item.perm !== 'H';
  };

  /**
   * 是否显示组件
   * @param itemObj 组件
   * @param hidden 是否隐藏
   */
  const labelShow = (itemObj: FormItemModel, hidden: boolean) => {
    if (!hidden) {
      if (hideFieldIds.value.indexOf(itemObj.id) !== -1) {
        hideFieldIds.value.splice(hideFieldIds.value.indexOf(itemObj.id), 1);
      }
    } else {
      if (hideFieldIds.value.indexOf(itemObj.id) === -1) {
        hideFieldIds.value.push(itemObj.id);
      }
    }
  };

  /** 监听 */
  watchEffect(() => {
    if (props.formItems != null) {
      let arr = {};
      loadFormConfig(props.formItems, arr);
      Object.assign(rules.value, arr);
    }
  });

  // 缓存下原始权限设置
  const formPermHis: any = ref({});

  // 比较函数
  const compare = (condition: any) => {
    //要判断组件类型，再取其值
    const source = _value.value[condition.field];
    const r = ref(false);
    //动态调用函数
    switch (condition.fieldType) {
      case 'AmountInput':
      case 'NumberInput':
      case 'Score':
      case 'CalcFormula':
        numCompareOptions.forEach((item) => {
          if (item.symbol == condition.compare) {
            r.value = item.compare(
              source,
              condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]],
            );
          }
        });
        break;
      case 'TextInput':
      case 'TextareaInput':
      case 'SelectInput':
      case 'Location':
      case 'Provinces':
        strCompareOptions.forEach((item) => {
          if (item.symbol == condition.compare) {
            r.value = item.compare(
              source,
              condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]],
            );
          }
        });
        break;
      case 'MultipleSelect':
        strArrCompareOptions.forEach((item) => {
          if (item.symbol == condition.compare) {
            r.value = item.compare(
              source,
              condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]],
            );
          }
        });
        break;
      case 'DateTime':
        timeCompareOptions.forEach((item) => {
          if (item.symbol == condition.compare) {
            r.value = item.compare(
              source,
              condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]],
            );
          }
        });
        break;
      case 'DateTimeRange':
        timeArrCompareOptions.forEach((item) => {
          if (item.symbol == condition.compare) {
            r.value = item.compare(
              source,
              condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]],
            );
          }
        });
        break;
      case 'DeptPicker':
      case 'UserPicker':
        orgCompareOptions.forEach((item) => {
          if (item.symbol == condition.compare) {
            r.value = item.compare(
              source,
              condition.fixed ? condition.compareVal : _value.value[condition.compareVal[0]],
            );
          }
        });
        break;
    }
    return r.value;
  };

  const hideField = (id: any) => {
    const field = formItemMap.value.get(id);
    if (field) {
      field['perm'] = 'H';
    }
  };
  const showField = (id: any) => {
    const field = formItemMap.value.get(id);
    if (field) {
      field['perm'] = formPermHis.value[id] || 'E';
    }
  };
  const disableField = (id: any) => {
    const field = formItemMap.value.get(id);
    if (field) {
      field['perm'] = 'R';
    }
  };
  const enableField = (id: any) => {
    const field = formItemMap.value.get(id);
    if (field) {
      field['perm'] = 'E';
    }
  };
  const updateField = (id: any, val: any) => {
    const field = formItemMap.value.get(id);
    if (field) {
      _value.value[id] = val;
    }
  };

  const doActions = async (actions: any) => {
    (actions || []).forEach((action: any) => {
      //执行预设的动作
      switch (action.type) {
        case 'SHOW':
          action.targets.forEach((tg: any) => showField(tg));
          break;
        case 'HIDE':
          action.targets.forEach((tg: any) => hideField(tg));
          break;
        case 'DISABLE':
          action.targets.forEach((tg: any) => disableField(tg));
          break;
        case 'UPDATE':
          action.targets.forEach((tg: any) => updateField(tg, action.value));
          break;
        case 'ENABLE':
          action.targets.forEach((tg: any) => enableField(tg));
          break;
      }
    });
  };

  // 解析表单联动规则
  const parserRule = (cdRule: any) => {
    const condition = cdRule.condition;
    //在这里可以实现一个算法，按条件层级去解析，不需要解析所有条件，先不实现
    if (cdRule.children.length > 0) {
      for (let i = 0; i < cdRule.children.length; i++) {
        const result = parserRule(cdRule.children[i]);
        if (cdRule.logic) {
          //如果是且关系，有一个为假就是假
          if (!result) {
            return false;
          }
        } else {
          //如果是或关系，有一个为真就是真
          if (result) {
            return true;
          }
        }
      }
      //遍历完了返回最终结果
      return cdRule.logic;
    } else {
      //解析条件
      try {
        const r = compare(condition);
        return r;
      } catch (e) {
        return false;
      }
    }
  };

  const analyseRules = () => {
    (props.formConfig.rules || []).forEach((rule: any, i: number) => {
      //解析表单联动条件
      const result = parserRule(rule.condition);
      console.log(`解析规则 ${i + 1}: ${result}`);
      doActions(result ? rule.action.with : rule.action.other);
    });
  };

  const execute: any = ref();
  const analyseJsRules = async () => {
    if (!(execute.value instanceof Function)) {
      execute.value = new Function(
        'formData',
        'formMap',
        `${props.formConfig.ruleJs || 'function doChange(){}'}\r\n doChange(formData, formMap);`,
      );
    }
    execute.value(props.formData, formItemMap.value);
  };

  const analyseFormRule = () => {
    if (props.formConfig.ruleType === 'SIMPLE') {
      analyseRules();
    } else {
      analyseJsRules();
    }
  };

  watch(
    [() => props.formConfig, () => props.formData],
    () => {
      if (props.formConfig) {
        if (Object.keys(formPermHis.value).length === 0) {
          formItemMap.value.forEach((item) => {
            formPermHis.value[item.id] = item.perm;
          });
        }
        analyseFormRule();
      }
    },
    { immediate: true, deep: true },
  );

  onLoad(() => {
    console.log('onload');
  });

  onShow(() => {
    console.log('onshow');
  });
</script>
<style scoped lang="scss">
  page {
    padding: 0 20rpx;
  }
</style>
